home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / CW MacMindy 1.4 / Examples / Toolbox / Simple.dyl < prev    next >
Encoding:
Text File  |  1995-11-15  |  12.4 KB  |  440 lines  |  [TEXT/CWIE]

  1. module:    Main
  2.  
  3. /*
  4.   Simple.dyl
  5.  
  6.   Simple Macintosh Application example for Mindy Dylan.
  7.                      
  8.   This demonstrates direct use of the Toolbox from Dylan.
  9.   It is not a good example of how Dylan SHOULD be used.    
  10.                      
  11.   by Patrick C. Beard.
  12. */
  13.                      
  14. define module Main
  15.   use dylan;
  16.   use extensions, import: { main, <equal-table>, <boolean> };
  17.   use cheap-io;
  18.   use threads;        // imports "spawn-thread".
  19.   use extern;        // imports "<c-string>".
  20.   use format, import: { format-to-string };
  21.   use Toolbox;        // imports "Debugger", etc.
  22. end module Main;
  23.  
  24. // menu constants.
  25.  
  26. define constant $MenuBar-ID =128;
  27.  
  28. define constant $Apple-Menu-ID = 128;
  29. define constant $About-Item = 1;
  30.  
  31. define constant $File-Menu-ID = 129;
  32. define constant $New-Item = 1;
  33. define constant $Close-Item = 2;
  34. define constant $Quit-Item = 4;
  35.  
  36. define constant $Edit-Menu-ID = 130;
  37.  
  38. define constant $Font-Menu-ID = 131;
  39.  
  40. // alert & dialog constants.
  41.  
  42. define constant $About-Alert-ID = 128;
  43. define constant $Document-Window-ID = 128;
  44. define constant $Cricket-snd-ID = 128;
  45.  
  46. // main!
  47.  
  48. define method main (argv0, #rest args)
  49.     let menuBar = GetNewMBar($MenuBar-ID);
  50.     if (menuBar ~= as(<MenuBarHandle>, 0))
  51.     SetMenuBar(menuBar);
  52.     FillMenu($Apple-Menu-ID, "DRVR");
  53.     FillMenu($Font-Menu-ID, "FONT");
  54.     DrawMenuBar();
  55.     EventLoop();
  56.     end if;
  57. end method main;
  58.  
  59. define method FillMenu(menuID :: <integer>, typestr :: <string>)
  60.     let menu = GetMenuHandle(menuID);
  61.     if (menu ~= $nil)
  62.     AppendResMenu(menu, os-type(typestr));
  63.     end if;
  64. end method FillMenu;
  65.  
  66. // get access to a C global that gets set when a "Quit" AppleEvent is received.
  67. define constant theTimeToQuit = find-c-pointer("theTimeToQuit");
  68. define constant collect-garbage = get-c-function("collect_garbage", args: #(), result: #());
  69.  
  70. // chirp like a cricket.
  71.  
  72. define constant $sound-resource-type = os-type("snd ");
  73.  
  74. define method chirp()
  75.     let sound = GetResource($Sound-resource-type, $Cricket-snd-ID);
  76.     if (sound ~= $nil)
  77.     SndPlay($nil, sound, #f);
  78.     ReleaseResource(sound);
  79.     end if;
  80. end method;
  81.  
  82. // an Alert event filter routine.
  83.  
  84. define method alert-filter (dialog :: <DialogPtr>, event :: <EventRecord>, itemHit :: <Ptr>)
  85.      => (result :: <boolean>);
  86.     //    Debugger();
  87.     if (event-what(event) = $keyDown)
  88.     chirp();
  89.     signed-short-at(itemHit) := 1;
  90.     #t;
  91.     else
  92.     #f;
  93.     end if;
  94. end method alert-filter;
  95.  
  96. define constant $alert-filter-callback = as (<ModalFilterUPP>,
  97.                          make-c-callback(alert-filter,
  98.                                  list(<DialogPtr>, <EventRecord>, <Ptr>),
  99.                                  <boolean>, $uppModalFilterProcInfo));
  100.  
  101. // create a thread that blinks a rectangle in the front-most window.
  102. define constant blink-rect = make(<Rect>, top: 1, left: 1, bottom: 3, right: 3);
  103.  
  104. define constant $qd-lock = make(<multilock>);
  105.  
  106. define method acquire-quickdraw (port :: <GrafPtr>)
  107.     grab-lock($qd-lock);
  108.     SetPort(port);
  109. end method acquire-quickdraw;
  110.  
  111. define method release-quickdraw ()
  112.     release-lock($qd-lock);
  113. end method release-quickdraw;
  114.  
  115. define variable *blinkers-running* = #t;
  116. define variable *blinker-exits* = 0;
  117. define constant $blinker-lock = make(<multilock>);
  118.  
  119. define method blinker (window :: <WindowPtr>, period :: <integer>)
  120.     let time-to-blink = TickCount() +  period;
  121.     while (*blinkers-running*)
  122.     if (TickCount() >= time-to-blink)
  123.         acquire-quickdraw(window);
  124.         InvertRect(blink-rect);
  125.         release-quickdraw();
  126.         time-to-blink := TickCount() +  period;
  127.     end if;        
  128.     end while;
  129.     // let the main event loop know we've exited the blinking phase by incrementing a counter.
  130.     grab-lock($blinker-lock);
  131.     *blinker-exits* := *blinker-exits* + 1;
  132.     release-lock($blinker-lock);
  133.     while (#t)
  134.     end while;
  135. end method blinker;
  136.  
  137. define method alarm-clock (h :: <integer>, m :: <integer>)
  138.     let time = as(<DateTimeRec>, NewPtr(14));
  139.     block(return)
  140.     while (#t)
  141.         SecondsToDate(GetDateTime(), time);
  142.         if (time.hour = h & time.minute = m)
  143.         SysBeep(1);
  144.         end if;
  145.     end while;
  146.     cleanup
  147.     destroy(time);
  148.     end block;
  149. end method;
  150.  
  151. define method EventLoop () => ();
  152.     // some variables we'll need.
  153.     let event = make(<EventRecord>);
  154.     let message = as(<Pascal-string>, "you typed: '?'");
  155.     let offset = size(message) - 2;
  156.     let itemString = make (<Pascal-string>);
  157.     let mouseRgn = NewRgn();
  158.     let textRect = make(<Rect>, bottom: 32, right: 100);
  159.     let sizeRect = make(<Rect>, top: 100, left: 100, bottom: 1000, right: 1000);
  160.     let blinker-count = 0;
  161.     let blinker-threads = make(<equal-table>);
  162.     let quit-signaled = #f;
  163.     
  164.     // set an alarm for a particular hour and minute.
  165.     // let alarm-thread = spawn-thread("alarm-clock", curry(alarm-clock, 8, 45));
  166.     
  167.     block (return)
  168.     // draw window here.
  169.     local method DrawWindow (window :: <WindowPtr>)
  170.           // make sure we own this window.
  171.           if (element(blinker-threads, window, default: #f) ~= #f)
  172.               acquire-quickdraw(window);
  173.               EraseRect(textRect);
  174.               MoveTo(10, 16);
  175.               DrawString(message);
  176.               DrawGrowIcon(window);
  177.               release-quickdraw();
  178.           end if;
  179.           end method;
  180.     
  181.     local method MakeWindow()
  182.           let window = GetNewWindow($Document-Window-ID);
  183.           if (window ~= $nil)
  184.               blinker-count := blinker-count + 1;
  185.               let thread-name = format-to-string("blinker %d", blinker-count);
  186.               let thread = spawn-thread(thread-name, curry(blinker, window, 10));
  187.               blinker-threads[window] := thread;
  188.           end if;
  189.           end method;
  190.     
  191.     local method RemoveWindow(window :: <WindowPtr>) => (result :: <boolean>);
  192.           let thread = element(blinker-threads, window, default: #f);
  193.           if (thread)
  194.               kill-thread(thread);
  195.               blinker-threads := remove-key!(blinker-threads, window);
  196.               DisposeWindow(window);
  197.               blinker-count := blinker-count - 1;
  198.               #t;
  199.           else
  200.               #f;
  201.           end if;
  202.           end method;
  203.     
  204.     local method DoAbout()
  205.           chirp();
  206.           Alert($About-Alert-ID, filter: $alert-filter-callback);
  207.           end method;
  208.     
  209.     // pre-process menu states.
  210.     local method UpdateMenus()
  211.           let fileMenu = GetMenuHandle($File-Menu-ID);
  212.           let fontMenu = GetMenuHandle($Font-Menu-ID);
  213.           if (FrontWindow() ~= $nil)
  214.               EnableItem(fileMenu, $Close-Item);
  215.               EnableItem(fontMenu, 0);
  216.           else
  217.               DisableItem(fileMenu, $Close-Item);
  218.               DisableItem(fontMenu, 0);
  219.           end if;
  220.           DrawMenuBar();
  221.           end method;
  222.     
  223.     // process menu selections.
  224.     local method DoMenu (menu, item)
  225.           if (menu ~= 0 & item ~= 0)
  226.               select (menu by \=)
  227.               $Apple-Menu-ID =>
  228.                   if (item = $About-Item)
  229.                   DoAbout();
  230.                   else
  231.                   GetMenuItemText(GetMenuHandle($Apple-Menu-ID), item, itemString);
  232.                   OpenDeskAcc(itemString);
  233.                   end if;
  234.               $File-Menu-ID =>
  235.                   select (item by \=)
  236.                   $New-Item =>
  237.                       MakeWindow();
  238.                   $Close-Item =>
  239.                       let window = FrontWindow();
  240.                       if (window ~= $nil)
  241.                       RemoveWindow(window);
  242.                       end if;
  243.                   $Quit-Item =>
  244.                       quit-signaled := #t;
  245.                       // return();
  246.                   end select;
  247.               $Font-Menu-ID =>
  248.                   let window = FrontWindow();
  249.                   if (window ~= $nil)
  250.                   GetMenuItemText(GetMenuHandle($Font-Menu-ID), item, itemString);
  251.                   let font-number = GetFNum(itemString);
  252.                   acquire-quickdraw(window);
  253.                   TextFont(font-number);
  254.                   DrawWindow(window);
  255.                   release-quickdraw();
  256.                   end if;
  257.               otherwise =>
  258.                   GetMenuItemText(GetMenuHandle(menu), item, itemString);
  259.                   DebugStr(itemString);
  260.               end select;
  261.           end if;
  262.           HiliteMenu(0);
  263.           UpdateMenus();
  264.           end method;
  265.     
  266.     local method RubberBand (window :: <WindowPtr>)
  267.           let where = event-where(event);
  268.           // create a <Point> on the stack.
  269.           let localWhere = stack-alloc(<Point>, 4);
  270.           localWhere.point-v := where.point-v;
  271.           localWhere.point-h := where.point-h;
  272.           acquire-quickdraw(window);
  273.           GlobalToLocal(localWhere);
  274.           release-quickdraw();
  275.           block (return)
  276.               // create a <Rect> on the stack.
  277.               let lassoRect = stack-alloc(<Rect>, 8);
  278.               lassoRect.top := point-v(localWhere);
  279.               lassoRect.left := point-h(localWhere);
  280.               lassoRect.bottom := point-h(localWhere);
  281.               lassoRect.right := point-v(localWhere);
  282.               acquire-quickdraw(window);
  283.               PenMode($patXor);
  284.               FrameRect(lassoRect);
  285.               release-quickdraw();
  286.               while (StillDown())
  287.               acquire-quickdraw(window);
  288.               GetMouse(localWhere);
  289.               release-quickdraw();
  290.               if (point-h(localWhere) ~= lassoRect.right | point-v(localWhere) ~= lassoRect.bottom)
  291.                   acquire-quickdraw(window);
  292.                   FrameRect(lassoRect);
  293.                   lassoRect.bottom := point-v(localWhere);
  294.                   lassoRect.right := point-h(localWhere);
  295.                   FrameRect(lassoRect);
  296.                   release-quickdraw();
  297.               end if;
  298.               end while;
  299.               acquire-quickdraw(window);
  300.               FrameRect(lassoRect);
  301.               PenMode($patOr);
  302.               release-quickdraw();
  303.           end block;
  304.           // print(localWhere);
  305.           // fflush();
  306.           values(#"chirp");
  307.           end method;
  308.     
  309.     // process mouse clicks.
  310.     local method DoClick (event :: <EventRecord>)
  311.           let (partCode, window) = FindWindow(event-where(event));
  312.           select (partCode)
  313.               $inMenuBar =>
  314.               UpdateMenus();
  315.               let (menu, item) = MenuSelect(event-where(event));
  316.               DoMenu(menu, item);
  317.               $inDesk =>
  318.               #f;
  319.               $inDrag =>
  320.               DragWindow(window, event-where(event));
  321.               $inContent =>
  322.               SelectWindow(window);
  323.               if (RubberBand(window) == #"chirp") chirp(); end if;
  324.               $inGoAway =>
  325.               if (TrackGoAway(window, event-where(event)))
  326.                   RemoveWindow(window);
  327.                   UpdateMenus();
  328.               end if;
  329.               $inZoomIn, $inZoomOut =>
  330.               if (TrackBox(window, event-where(event), partCode))
  331.                   acquire-quickdraw(window);
  332.                   EraseRect(window.portRect);
  333.                   ZoomWindow(window, partCode, #t);
  334.                   release-quickdraw();
  335.               end if;
  336.               $inGrow =>
  337.               let (height, width) = GrowWindow(window, event-where(event), sizeRect);
  338.               if (height ~= 0 & width ~= 0)
  339.                   acquire-quickdraw(window);
  340.                   SizeWindow(window, width, height, #f);
  341.                   EraseRect(window.portRect);
  342.                   DrawWindow(window);
  343.                   release-quickdraw();
  344.               end if;
  345.               otherwise =>
  346.               #f;
  347.           end select;
  348.           end method;
  349.     
  350.     // process keystrokes.
  351.     local method DoKey (event :: <EventRecord>)
  352.           let ch = as(<character>, logand(event-message(event), 255));
  353.           if (logand(event-modifiers(event), $cmdKey) = $cmdKey)
  354.               UpdateMenus();
  355.               let (menu, item) = MenuKey(ch);
  356.               DoMenu(menu, item);
  357.           else
  358.               message[offset] := ch;
  359.               let window = FrontWindow();
  360.               if (window ~= $nil)
  361.               DrawWindow(window)
  362.               else
  363.               DebugStr(message);
  364.               end if;
  365.               // break("yes: %=", ch);
  366.           end if;
  367.           end method;
  368.     
  369.     // process update events.
  370.     local method DoUpdate (event :: <EventRecord>)
  371.           let window = as(<WindowPtr>, event-message(event));
  372.           BeginUpdate(window);
  373.           DrawWindow(window);
  374.           EndUpdate(window);
  375.           end method;
  376.     
  377.     // process activate events.
  378.     local method DoActivate (event :: <EventRecord>)
  379.           let window = as(<WindowPtr>, event-message(event));
  380.           DrawWindow(window);
  381.           end method;
  382.     
  383.     // override the default Quit AppleEvent handler.
  384.     local method HandleQuitEvent (event :: <AppleEvent>, reply :: <AppleEvent>, refCon :: <integer>)
  385.            => (result :: <OSErr>);
  386.           quit-signaled := #t;
  387.           values(0);
  388.           end method;
  389.     
  390.     let quit-handler = as (<AEEventHandlerUPP>,
  391.                    make-c-callback(HandleQuitEvent, list(<AppleEvent>, <AppleEvent>, <integer>),
  392.                            <OSErr>, $uppAEEventHandlerProcInfo));
  393.     
  394.     let result = AEInstallEventHandler($kCoreEventClass, $kAEQuitApplication, quit-handler, 0, #f);
  395.     
  396.     // get initial state right.
  397.     UpdateMenus();
  398.     
  399.     // the event loop goes on until somebody quits.
  400.     while (~quit-signaled)
  401.         if (WaitNextEvent($everyEvent, event, 5, mouseRgn))
  402.         select (event-what(event))
  403.             $mouseDown =>
  404.             DoClick(event);
  405.             $keyDown =>
  406.             DoKey(event);
  407.             $updateEvt =>
  408.             DoUpdate(event);
  409.             $activateEvt =>
  410.             DoActivate(event);
  411.             $kHighLevelEvent =>
  412.             result := AEProcessAppleEvent(event);
  413.             otherwise =>
  414.             #f;
  415.         end select;
  416.         end if;
  417.     end while;
  418.     
  419.     // shut down all the blinker threads.
  420.     *blinkers-running* := #f;
  421.     while (*blinker-exits* ~= blinker-count)
  422.     end while;
  423.     
  424.     // close all the windows.
  425.     for (window in key-sequence(blinker-threads))
  426.         RemoveWindow(window);
  427.     end for;
  428.     
  429.     cleanup
  430.     destroy(event);
  431.     destroy(message);
  432.     destroy(itemString);
  433.     DisposeRgn(mouseRgn);
  434.     destroy(textRect);
  435.     destroy(sizeRect);
  436.     // kill-thread(alarm-thread);
  437.     destroy-callbacks();
  438.     end block;
  439. end method EventLoop;
  440.